package org.geektimes.management;

import java.beans.IntrospectionException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;
import javax.management.Descriptor;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.RuntimeOperationsException;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.InvalidTargetObjectTypeException;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanConstructorInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;

public class HelloWorldModelMBean extends RequiredModelMBean {
	public HelloWorldModelMBean() throws Exception {
	}

	public static RequiredModelMBean createModelBean(Object o) throws RuntimeOperationsException, MBeanException,
			InstanceNotFoundException, InvalidTargetObjectTypeException {
		// 模型MBean信息
		ModelMBeanInfo info = buildModelMBeanInfo(o);
		// 模型MBean
		RequiredModelMBean modelMBean = new RequiredModelMBean(info);
		// 目前只支持ObjectReference，将来可能会支持ObjectReference", "Handle", "IOR", "EJBHandle",
		// or "RMIReference，
		// RMIReference从名字上可以看出，如果支持的话，那么以后就可以支持远程MBean引用
		modelMBean.setManagedResource(o, "ObjectReference");
		return modelMBean;
	}

	protected static ModelMBeanInfo buildModelMBeanInfo(Object o) throws RuntimeOperationsException, MBeanException {

		// BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass());

		// beanInfo.getPropertyDescriptors();

		// --
		// attributes
		// ------------------------------------------------------------------
		ModelMBeanAttributeInfo[] attributes = new ModelMBeanAttributeInfo[1];

		// 设置属性
		Descriptor nameDesc = new DescriptorSupport();
		nameDesc.setField("name", "world");
		nameDesc.setField("displayName", "Name");
		nameDesc.setField("setMethod", "setName");
		nameDesc.setField("getMethod", "getName");
		nameDesc.setField("descriptorType", "attribute");
		attributes[0] = new ModelMBeanAttributeInfo("name", "java.lang.String", "name say hello to", true, true, false,
				nameDesc);
		// --
		// operations
		// -------------------------------------------------------------------
		ModelMBeanOperationInfo[] operations = new ModelMBeanOperationInfo[3];
		String className = Hello.class.getName();

		// getName method
		Descriptor getDesc = new DescriptorSupport(new String[] { "name=getName", "descriptorType=operation",
				"class=" + className, "role=operation" });
		operations[0] = new ModelMBeanOperationInfo("getName", "get name", null, "java.lang.String", MBeanOperationInfo.INFO,
				getDesc);

		Descriptor setDesc = new DescriptorSupport(new String[] { "name=setName", "descriptorType=operation",
				"class=" + className, "role=operation" });
		operations[1] = new ModelMBeanOperationInfo("setName", "set Name  ",
				new MBeanParameterInfo[] { new MBeanParameterInfo("name", "java.lang.String", " name method's arg ") }, null,
				MBeanOperationInfo.ACTION, setDesc);

		// constructors
		ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[1];
		Constructor<?>[] ctors = Hello.class.getConstructors();

		constructors[0] = new ModelMBeanConstructorInfo("default constructor", ctors[0], null);

		// ModelMBeanInfo
		ModelMBeanInfo mmbeanInfo = new ModelMBeanInfoSupport(className, "Simple implementation of model bean.",
				attributes, constructors, operations/* null */, null, null);

		// 设置一个Descriptor策略，这样RequiredModelMBean改变 Attribute值得时候会记录日志
		//
		// 当然RequiredModelMBean还需要addAttributeChangeNotificationListener，注册一个监听器
		Descriptor globalDescriptor = new DescriptorSupport(new String[] { "name=HelloWorldModelMBean",
				"displayName=globaldescriptor", "descriptorType=mbean", "log=T", "logfile=hello.log" });
		mmbeanInfo.setMBeanDescriptor(globalDescriptor);
		
		return mmbeanInfo;
	}

}